﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

namespace Dapper.Sharding
{
    public class ConfigSystemTextJson
    {
        private readonly static JsonSerializerOptions opt = new JsonSerializerOptions()
        {
            //Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), //不编码中文
            //PropertyNamingPolicy = null, //序列化属性不转小写
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,//不编码中文和html
            NumberHandling = JsonNumberHandling.AllowReadingFromString, //反序列化时允许string转数字
            PropertyNameCaseInsensitive = true, //反序列化忽略大小写
            ReadCommentHandling = JsonCommentHandling.Skip, //跳过注释
            AllowTrailingCommas = true  //允许尾部逗号
        };

        public static JsonObject LoadObject(string jsonFile, string key = null)
        {
            var file = $"{AppDomain.CurrentDomain.BaseDirectory}{jsonFile}";
            var text = File.ReadAllText(file);
            var obj = JsonSerializer.Deserialize<JsonObject>(text, opt);

            if (!string.IsNullOrEmpty(key))
            {
                obj = obj[key].AsObject();
            }
            return obj;
        }

        public static ClientConfig LoadConfig(JsonObject obj)
        {
            var cfg = new ClientConfig();
            cfg.Config = obj.Deserialize<DataBaseConfig>(opt);

            if (obj.TryGetPropertyValue("AutoCreateDatabase", out JsonNode node))
            {
                cfg.AutoCreateDatabase = node.GetValue<bool>();
            }

            if (obj.TryGetPropertyValue("AutoCreateTable", out node))
            {
                cfg.AutoCreateTable = node.GetValue<bool>();
            }

            if (obj.TryGetPropertyValue("AutoCompareTableColumn", out node))
            {
                cfg.AutoCompareTableColumn = node.GetValue<bool>();
            }

            if (obj.TryGetPropertyValue("AutoCompareTableColumnLength", out node))
            {
                cfg.AutoCompareTableColumnLength = node.GetValue<bool>();
            }

            if (obj.TryGetPropertyValue("AutoCompareTableColumnDelete", out node))
            {
                cfg.AutoCompareTableColumnDelete = node.GetValue<bool>();
            }

            if (obj.TryGetPropertyValue("Database", out node))
            {
                cfg.Database = node.GetValue<string>();
            }

            if (obj.TryGetPropertyValue("Id", out node))
            {
                cfg.Id = node.GetValue<string>();
            }

            if (obj.TryGetPropertyValue("DatabaseList", out node))
            {
                cfg.DatabaseList = node.Deserialize<List<string>>();
            }

            cfg.DbType = DataBaseType.MySql;
            if (obj.TryGetPropertyValue("DbType", out node))
            {
                var dbType = node.GetValue<string>().ToLower();
                if (dbType == "mysql" || dbType == "mariadb")
                {
                    cfg.DbType = DataBaseType.MySql;
                }
                else if (dbType == "postgresql" || dbType == "pgsql")
                {
                    cfg.DbType = DataBaseType.Postgresql;
                }
                else if (dbType == "sqlserver")
                {
                    cfg.DbType = DataBaseType.SqlServer;
                }
                else if (dbType == "oracle")
                {
                    cfg.DbType = DataBaseType.Oracle;
                }
                else if (dbType == "sqlite")
                {
                    cfg.DbType = DataBaseType.Sqlite;
                }
                else if (dbType == "clickhouse" || dbType == "ck")
                {
                    cfg.DbType = DataBaseType.ClickHouse;
                }
                else if (dbType == "duckdb" || dbType == "duck")
                {
                    cfg.DbType = DataBaseType.DuckDB;
                }
                else if (dbType == "saphana" || dbType == "hana" || dbType == "sap" || dbType == "saphanadb")
                {
                    cfg.DbType = DataBaseType.SapHana;
                }
                else
                {
                    throw new Exception($"unknown DbType==>{dbType}");
                }
            }

            cfg.DbVersion = DataBaseVersion.Default;
            if (obj.TryGetPropertyValue("DbVersion", out node))
            {
                var version = node.GetValue<string>().ToLower();
                if (version == "sqlserver2005")
                {
                    cfg.DbVersion = DataBaseVersion.SqlServer2005;
                }
                else if (version == "sqlserver2008")
                {
                    cfg.DbVersion = DataBaseVersion.SqlServer2008;
                }
                else if (version == "sqlserver2012")
                {
                    cfg.DbVersion = DataBaseVersion.SqlServer2012;
                }
            }

            return cfg;
        }

        public static ClientConfig LoadConfig(string jsonFile, string key = null)
        {
            var obj = LoadObject(jsonFile, key);
            return LoadConfig(obj);
        }

        public static JsonArray LoadArray(string jsonFile, string key = null)
        {
            var file = $"{AppDomain.CurrentDomain.BaseDirectory}{jsonFile}";
            var text = File.ReadAllText(file);
            if (!string.IsNullOrEmpty(key))
            {
                var obj = JsonSerializer.Deserialize<JsonObject>(text, opt);
                return obj[key].AsArray();
            }

            return JsonSerializer.Deserialize<JsonArray>(text, opt);
        }

        public static List<ClientConfig> LoadConfigList(JsonArray array)
        {
            var list = new List<ClientConfig>();
            foreach (var item in array.Cast<JsonObject>())
            {
                list.Add(LoadConfig(item));
            }
            return list;
        }

        public static List<ClientConfig> LoadConfigList(string jsonFile, string key = null)
        {
            var array = LoadArray(jsonFile, key);
            return LoadConfigList(array);
        }
    }
}
